#include "at_parser.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "queue.h"

#define AT_PREFIX               "\r\n"      //前缀
#define AT_SUFFIX               "\r\n"      //后缀
#define AT_PREFIXASUFFIX        "\r\n\r\n"

static char* memstr(const void* src,const char* sub,int size)
{
    int subSize = 0;
    int i = 0;
    int lenDiff = 0;
    if (!src || !sub)
        return NULL;
    subSize = strlen(sub);
    if (subSize > size)
        return NULL;
    lenDiff = size - subSize;
    for (i = 0; i < lenDiff; i++)
    {
        if (memcmp((char*)src + i, sub, subSize) == 0)
        {
            return (char*)src + i;
        }
    }
    
    return NULL;
}

static int at_get_line(ATConfig* cfg,const char* headCmd,int size, char* payLoadCmd, const char** nextHead)
{
    const char* prefix = 0;
    const char* prefixAsuffix = 0;
    const char* payloadHead = 0;
    int len = 0;
    if (headCmd == 0)
        return 0;
    prefix = memstr(headCmd, AT_PREFIX,size);
    if (prefix)
    {
        payloadHead = prefix + strlen(AT_PREFIX);
        size = size - (prefix + strlen(AT_PREFIX) - headCmd);
        prefixAsuffix = memstr(prefix + strlen(AT_PREFIX), AT_PREFIXASUFFIX, size);       //寻找"\r\n\r\n"
        if (prefixAsuffix)
        {
            *nextHead = prefixAsuffix + strlen(AT_SUFFIX);                       //重新定位到"\r\n"
            len = prefixAsuffix - prefix - strlen(AT_PREFIX);
            memcpy(payLoadCmd, payloadHead, len);
            payLoadCmd[len] = 0;
        }
        else
        {
            *nextHead = 0;
            len = size;
            memcpy(payLoadCmd, payloadHead, len);
            payLoadCmd[len] = 0;
        }
    }
    else
    {
        memcpy(payLoadCmd, headCmd,size);
        return size;
    }

    return len;
    
}

//判断ATConfig是否合法
AT_ERROR    at_config_vaild(ATConfig *cfg)
{
    if(cfg && cfg->atPort->fpUartInit && cfg->atPort->fpUartDeinit && cfg->atPort->fpUartSend && cfg->atPort->fpUartRead && cfg->fpSystick)
    {
        return AT_ERR_NONE;
    }
    return AT_ERR_PARAM_INVAILD;
}

//初始化
void at_parser_init(ATConfig *cfg)
{
    if(at_config_vaild(cfg) == AT_ERR_NONE)
    {
        cfg->atPort->fpUartInit();
    }
}

//反初始化
void at_parser_deinit(ATConfig *cfg)
{
    if(at_config_vaild(cfg) == AT_ERR_NONE)
    {
        cfg->atPort->fpUartDeinit();
    }
}

//处理URC事件
AT_ERROR at_urc_handle(ATConfig *cfg,const char* data,int len)
{
    int i = 0;
    for(i = 0;i < MAX_URC_NUM;i++)
    {
        if(cfg->sATURCCfg[i].ucURCHead && strncmp(cfg->sATURCCfg[i].ucURCHead,data,strlen(cfg->sATURCCfg[i].ucURCHead)) == 0)
        {
            cfg->sATURCCfg[i].pURCHandle(cfg->sATURCCfg[i].pvURCArg,data,len);
            return AT_ERR_NONE;
        }
    }
    return AT_ERR_NO_URC;
}

//读取和处理指令数据
static AT_ERROR     at_parser_read_handle(ATConfig *cfg,const char* will,pATCmdHandle handle,void* arg)
{
    int size = cfg->atPort->fpUartRead(cfg->cReceiveBuff,sizeof(cfg->cReceiveBuff));
	AT_ERROR	eATerror =AT_ERR_NO_WILL;
    if(size)        //读取到数据
    {
        //首先查看URC列表
        char *cmdPayload = (char*)malloc(size);
        const char* cmdHead = (const char*)cfg->cReceiveBuff;
        const char* nextHead = 0;
        int payloadLen = 0;
        cfg->cReceiveBuff[size] = 0;
        //
		if(cmdPayload == NULL)
		{
			if(cfg->iLogEnable)
				printf("Payload buffer error!\r\n");
			return eATerror;
		}
        if(cfg->iLogEnable)
            printf("%s",cfg->cReceiveBuff);
        while((payloadLen = at_get_line(cfg,cmdHead,size,cmdPayload,&nextHead))>0)
        {
            //printf("Line Head:%s\r\n",cmdPayload);
			if(AT_ERR_NO_URC == at_urc_handle(cfg,cmdPayload,payloadLen))
            {
                if(strstr(cfg->cReceiveBuff,"ERROR"))
                {
                    if(handle)
                        handle(arg,(const char*)cfg->cReceiveBuff,size,AT_ERR_ERROR);
					eATerror = AT_ERR_ERROR;
					//goto safe_free;
                }
                if(will)
                {
                    if(strstr(cfg->cReceiveBuff,will))
                    {
                        if(handle)
                            handle(arg,(const char*)cfg->cReceiveBuff,size,AT_ERR_NONE);
						eATerror = AT_ERR_NONE;
						//goto safe_free;
                    }
                }
            }
			
            if(nextHead)
                size = size - (nextHead - cmdHead);
            cmdHead = nextHead;
            
        }
		//eATerror = AT_ERR_NO_WILL;
safe_free:
		free(cmdPayload);
        return eATerror;
    }
    else
        return AT_ERR_READ_NONE;
}

//循环
void at_parser_loop(ATConfig *cfg)
{
    AT_ERROR err;
    if(at_config_vaild(cfg) != AT_ERR_NONE)
        return;
    switch(cfg->eATCmdStatus)
    {
        case AT_CMD_IDLE:
            if(!queue_empty(&cfg->qATQueue))
            {
                ATCmdConfig* cmdCfg = (ATCmdConfig*)queue_top(&cfg->qATQueue);
                if(cmdCfg)
                {
                    cfg->atPort->fpUartSend(cmdCfg->at_cmd,cmdCfg->at_len);
                    cfg->eATCmdStatus = AT_CMD_WAIT;
                    cfg->ulCurrentTimeout = cfg->fpSystick();
                }
            }
            else
                at_parser_read_handle(cfg,0,0,0);
            break;
        case AT_CMD_WAIT:
            if(!queue_empty(&cfg->qATQueue))
            {
                ATCmdConfig* cmdCfg = (ATCmdConfig*)queue_top(&cfg->qATQueue);
                if(cfg->fpSystick() - cfg->ulCurrentTimeout < cmdCfg->timeout)
                {
                    err = at_parser_read_handle(cfg,cmdCfg->at_will,cmdCfg->handler,cmdCfg->arg);
                    if(err == AT_ERR_NONE || err == AT_ERR_ERROR)
                    {
                        free(cmdCfg);
                        queue_pop(&cfg->qATQueue);
                        cfg->eATCmdStatus = AT_CMD_IDLE;
                    }
                }
                else
                {
                    if(cmdCfg->resendCnt)
                        cmdCfg->resendCnt--;
                    if(cmdCfg->resendCnt)
                    {
                        cfg->atPort->fpUartSend(cmdCfg->at_cmd,cmdCfg->at_len);
                        cmdCfg->timeout = cfg->fpSystick() + cmdCfg->timeout;
                    }
                    else
                    {
                        free(cmdCfg);
                        queue_pop(&cfg->qATQueue);
                        cfg->eATCmdStatus = AT_CMD_IDLE;
                    }
                }
            }
            else
            {
                cfg->eATCmdStatus = AT_CMD_IDLE;
            }
            break;
        default:break;
    }
}

//非阻塞发送AT
AT_ERROR at_parser_send_no_wait(ATConfig *cfg,const char* cmd,int atLen,const char* will,pATCmdHandle handler,void* arg,uint32_t timeout,uint8_t resendCnt)
{
    ATCmdConfig *cmdCfg = (ATCmdConfig*)malloc(sizeof(ATCmdConfig));
    if(cmdCfg)
    {
        cmdCfg->at_cmd = cmd;
        cmdCfg->at_len = atLen;
        cmdCfg->at_will = will;
        cmdCfg->handler = handler;
        cmdCfg->arg = arg;
        cmdCfg->timeout = timeout;
        cmdCfg->resendCnt = resendCnt;
        if(queue_push(&cfg->qATQueue,cmdCfg))
            return AT_ERR_NONE;
        else
        {
            free(cmdCfg);
            return AT_ERR_FULL;
        }
    }
    else
        return AT_ERR_FULL;
}

//阻塞发送AT指令
AT_ERROR  at_parser_send_wait(ATConfig *cfg,const char* cmd,int atLen,const char* will,const char** recBuff,uint32_t timeout,uint8_t resendCnt)
{
    AT_ERROR err = AT_ERR_NONE;
    unsigned long ulTick = 0;
    
    err = at_config_vaild(cfg);
    if(err != AT_ERR_NONE)
        return err;
    if(cfg->eATCmdStatus == AT_CMD_WAIT)
        return AT_ERR_DEALING;
    do
    {
        cfg->atPort->fpUartSend(cmd,atLen);
        if(cfg->iLogEnable)
            printf("%s",cmd);
        ulTick = cfg->fpSystick();
        while(cfg->fpSystick() - ulTick < timeout)
        {
            err = at_parser_read_handle(cfg,will,0,0);
            if(recBuff)
                *recBuff = cfg->cReceiveBuff;
            if(err == AT_ERR_NONE || err == AT_ERR_ERROR)
                return err;
        }
        if(resendCnt)
            resendCnt--;
    }while(resendCnt);
    return AT_ERR_TIMEOUT;
}

//直接发送数据
AT_ERROR at_parser_send(ATConfig *cfg,const char* cmd,int atLen)
{
	AT_ERROR err = AT_ERR_NONE;
    
    err = at_config_vaild(cfg);
    if(err != AT_ERR_NONE)
        return err;
    if(cfg->eATCmdStatus == AT_CMD_WAIT)
        return AT_ERR_DEALING;

	cfg->atPort->fpUartSend(cmd,atLen);
	if(cfg->iLogEnable)
		printf("%s",cmd);
	return AT_ERR_NONE;
}

//读入数据
AT_ERROR at_parser_read(ATConfig *cfg,unsigned char* buff,int *len,int maxLen,int timeout)
{
	AT_ERROR err = AT_ERR_NONE;
    unsigned long ulTick = 0;
    
    err = at_config_vaild(cfg);
    if(err != AT_ERR_NONE)
        return err;
    if(cfg->eATCmdStatus == AT_CMD_WAIT)
        return AT_ERR_DEALING;

    ulTick = cfg->fpSystick();
	while(cfg->fpSystick() - ulTick < timeout)
	{
		int readLen = cfg->atPort->fpUartRead((char*)buff,maxLen);
		if(readLen)
		{
			if(cfg->iLogEnable)
				printf("%s",(char*)buff);
			*len = readLen;
			buff[readLen] = 0;
			return err;
		}
	}
	*len = 0;
    return err;
}

//注册URC事件回调函数
AT_ERROR at_parser_register_urc(ATConfig *cfg,const char* cmd,pATCmdURCHandle f,void* arg)
{
    uint8_t i = 0;
    for(i = 0;i < MAX_URC_NUM;i++)
    {
        if(cfg->sATURCCfg[i].ucURCHead == 0)
        {
            cfg->sATURCCfg[i].ucURCHead = cmd;
            cfg->sATURCCfg[i].pURCHandle = f;
            cfg->sATURCCfg[i].pvURCArg = arg;
            break;
        }
    }
    return AT_ERR_NONE;
}


//启用日志
void at_parser_log(ATConfig *cfg,int enable)
{
    cfg->iLogEnable = enable;
}
